package rockpaperscissor;

import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class Server extends JFrame {

    private Semaphore locks = new Semaphore(2);
    private Semaphore answers = new Semaphore(2);
    private Game game = new Game();
    private GameFactory gf;
    private int clientNo;
// Text area for displaying contents
    private JTextArea jta = new JTextArea();

    public static void main(String[] args) {
        new Server();
    }

    public Server() {
// Place text area on the frame
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(new JScrollPane(jta), BorderLayout.CENTER);

        setTitle("MultiThreadServer");
        setSize(500, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true); // It is necessary to show the frame here!

        try {
// Create a server socket
            ServerSocket serverSocket = new ServerSocket(8000);
            jta.append("MultiThreadServer started at " + new Date() + '\n');

// Number a client
            clientNo = 1;

            while (true) {
// Listen for a new connection request
                Socket socket = serverSocket.accept();

// Display the client number
                jta.append("Starting thread for client " + clientNo
                        + " at " + new Date() + '\n');

// Find the client's host name, and IP address
                InetAddress inetAddress = socket.getInetAddress();
                jta.append("Client " + clientNo + "'s host name is "
                        + inetAddress.getHostName() + "\n");
                jta.append("Client " + clientNo + "'s IP Address is "
                        + inetAddress.getHostAddress() + "\n");

// Create a new thread for the connection
                Server.GameFactory thread = new Server.GameFactory(socket, clientNo);

// Start the new thread
                thread.start();




            }
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }

// Inner class
// Define the thread class for handling new connection
    class GameFactory extends Thread {

        private int pId;
        private Socket socket; // A connected socket

        /**
         * Construct a thread
         */
        public GameFactory(Socket socket, int pId) {
            this.socket = socket;
            this.pId = pId;
        }

        /**
         * Run a thread
         */
        public void run() {
            try {

// Create data input and output streams
                DataInputStream inputFromClient = new DataInputStream(
                        socket.getInputStream());
                DataOutputStream outputToClient = new DataOutputStream(
                        socket.getOutputStream());
                
                while(locks.availablePermits()==0){
                    gf=this;
                    
                    synchronized(this){
                        try {
                            outputToClient.writeInt(7);
                            wait();
                        } catch (InterruptedException ex) {
                            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                    
                }
                // Increment clientNo
                synchronized (this) {
                    clientNo++;
                }

                try {
                    locks.acquire();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (locks.availablePermits() > 0) {
                    Thread.currentThread().setName("Player 1");
                    jta.append("Waiting for a client...");
                } else {
                    Thread.currentThread().setName("Player 2");
                }
                synchronized (this) {
                    while (locks.availablePermits() > 0) {
                        gf = this;
                        try {
                            wait();
                        } catch (InterruptedException ex) {
                            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
                synchronized (gf) {
                    if (locks.availablePermits() == 0) {
                        gf.notify();
                    }
                }

                outputToClient.writeInt(pId);

                int choice = inputFromClient.readInt();

                jta.append(Thread.currentThread().getName() + " choose " + choice + "\n");
                game.addChoice(choice, pId);

                try {
                    answers.acquire();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }

                while (answers.availablePermits() > 0) {
                    gf = this;
                    synchronized (this) {
                        try {
                            wait();
                        } catch (InterruptedException ex) {
                            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
                if (answers.availablePermits() == 0) {
                    synchronized (gf) {
                        gf.notify();
                    }
                }

                outputToClient.writeInt(game.getWinner());

                synchronized (this) {
                    clientNo--;
                }


                locks.release();
                    try {
                        Thread.sleep(1000); //för att ge andra tråden en chans att komma ur loopen
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    answers.release();


            } catch (IOException e) {
                System.err.println(e);
            }
        }
    }
}